//
//  Network.swift
//  Extend
//
//  Created by 元穗 on 2017/5/19.
//  Copyright © 2017年 yuansui. All rights reserved.
//

import Alamofire
import HandyJSON
import SwiftyJSON

public protocol NetworkProvider {
    func load(id: Int, req: NetworkReq, listener: OnNetworkListener);
    func load<T: HandyJSON>(id: Int, req: NetworkReq, listener: OnNetworkListener, model: T);
    func upload(id:Int, req:NetworkReq, listener: OnNetworkListener);
    func download(id:Int, req:NetworkReq, listener: OnNetworkListener);
}

open class Network {
    private var provider: NetworkProvider;
    private var listener: OnNetworkListener;
    private var tag: String;

    static fileprivate var config: NetworkConfig?;

    public init(tag: String, listener: OnNetworkListener) {
        self.listener = listener;
        self.tag = tag;

        provider = AlamofireProvider();
    }

    public class func initialize(_ config: NetworkConfig) {
        self.config = config;
    }

    public func load<T:HandyJSON>(id: Int, req: NetworkReq, listener: OnNetworkListener, model: T) {
        provider.load(id: id, req: req, listener: listener, model: model)
    }
    
    public func load(id: Int, req: NetworkReq, listener: OnNetworkListener) {
        provider.load(id: id, req: req, listener: listener);
    }
    
    public func upload(id: Int, req: NetworkReq, listener: OnNetworkListener) {
        provider.upload(id: id, req: req, listener: listener);
    }
    
    public func download(id: Int, req: NetworkReq, listener: OnNetworkListener) {
        provider.download(id: id, req: req, listener: listener);
    }

    public func cancel(id: Int) {
        
    }

    public func cancelAll() {

    }
    
    
}

class AlamofireProvider: NetworkProvider {
    var manager:SessionManager?
    
    init() {
        let configure = URLSessionConfiguration.default;
        configure.timeoutIntervalForRequest = 10;
        manager = Alamofire.SessionManager(configuration:configure);
        
    }
    
    func load(id: Int, req: NetworkReq, listener: OnNetworkListener) {
        Log.d(req.url!);

        // 转换req的method到Al的method
        var method = HTTPMethod.get;
        switch req.method {
        case .Get:
            method = .get;
        case .Post:
            method = .post;
        case .Upload:
            method = .post;
        case .Download:
            method = .get;
        }
        if req.method == .Get || req.method == .Post {
            loadReq(id: id, req: req, method: method, listener: listener);
        } else if req.method == .Download {
            download(id: id, req: req, listener: listener);
        } else if req.method == .Upload {
            upload(id: id, req: req, listener: listener)
        }
    }
    
    final func upload(id: Int, req: NetworkReq, listener: OnNetworkListener) {
        Alamofire.upload(multipartFormData: { (mData) in
            mData.append(req.fileArrs![0] as! Data, withName: "file", fileName: "", mimeType: "image/jpeg/png")
            
            for (key, value) in req.params! {
                mData.append(value.data(using: String.Encoding.utf8)!, withName: key)
            }
        },
                         usingThreshold: 100000000,
                         to: URL.init(string: req.url!)!,
                         method: HTTPMethod.post,
                         headers: req.headers)
        { (encodingResult) in
            switch encodingResult {
            case .success(let upload, _, _):
                upload.responseJSON { response in
                    print("\(response)")
                    listener.onNetworkSuccess(id: id, result: response.value as AnyObject);
                    //                if let value = response.result.value as? [String: AnyObject] {
                    //                    success(value)
                    //                    let json = JSON(value)
                    //                    PrintLog(json)
                    //                }
                }
//            case .failure(let encodingError: Error):
//            PrintLog(encodingError)
//            failture(encodingError)
            default:
                print("default")
                listener.onNetworkErr(id: id, err: ParseErr(id, "上传出错"))
            }
        }
    }

    internal func loadReq(id: Int, req: NetworkReq, method: HTTPMethod, listener: OnNetworkListener) {
        Alamofire.request(req.url!, method: method, parameters: req.params).responseString { response in
            //            print(response.request)  // original URL request
            //            print(response.response) // HTTP URL response
            //            print(response.data)     // server data
            //            print(response.result)   // result of response serialization
            
            switch response.result {
            case .success(let value):
                
//                var jsss = JSON(response.data);
//                print(jsss["codxe"].stringValue)
//                print(jsss)
//                print("\n返回的JSON数据:\n");
//                print(value);
//                print("\n");
                if !value.isEmpty {
                    let resp = NetworkResp();
                    resp.setText(value);
                    resp.setData(response.data)
                    var result:String?;
//                    let result = listener.onNetworkResponse(id: id, resp: resp);
//                    let ttt = listener.onNetworkResponse(id: id, resp: resp, t: HandyJSON)
                    if result != nil {
                        listener.onNetworkSuccess(id: id, result: result as AnyObject);
                    } else {
                        listener.onNetworkErr(id: id, err: ParseErr(id, "解析出错"));
                    }
                }
            case .failure(let error):
                listener.onNetworkErr(id: id, err: ParseErr(id, JXLanguageTool.language(String.localized_Common_tips_netDisable)));
            }
//            if response.result.isSuccess {
//                if let JSON = response.result.value {
//                    let str = "\(JSON)";
//                    
//                    print("\n返回的JSON数据:\n");
//                    print(str);
//                    print("\n");
//                    
//                    let resp = NetworkResp();
//                    resp.setText(str);
//                    
//                    let result = listener.onNetworkResponse(id: id, resp: resp);
//                    if result != nil {
//                        listener.onNetworkSuccess(id: id, result: result);
//                    } else {
//                        listener.onNetworkErr(id: id, err: ParseErr(id, "解析出错"));
//                    }
//                    
//                } else {
//                    listener.onNetworkErr(id: id, err: ParseErr(id, "转换出错"));
//                }
//            } else {
//                listener.onNetworkErr(id: id, err: ParseErr(id, response.result.error.debugDescription));
//            }
        }
    }
    
    
    func load<T: HandyJSON>(id: Int, req: NetworkReq, listener: OnNetworkListener, model: T) {
        Log.d(req.url!);
        
        // 转换req的method到Al的method
        var method = HTTPMethod.get;
        switch req.method {
        case .Get:
            method = .get;
        case .Post:
            method = .post;
        case .Upload:
            method = .post;
        case .Download:
            method = .get;
        }
        if req.method == .Get || req.method == .Post {
            loadReq(id: id, req: req, method: method, listener: listener, model: model);
        } else if req.method == .Download {
            download(id: id, req: req, listener: listener);
        } else if req.method == .Upload {
            upload(id: id, req: req, listener: listener, model: model)
        }
    }
    
    internal func loadReq<T: HandyJSON>(id: Int, req: NetworkReq, method: HTTPMethod, listener: OnNetworkListener, model: T) {
        
        
        manager!.request(req.url!, method: method, parameters: req.params, headers:req.headers).responseString { response in
//            print(response.response?.statusCode)
            switch response.result {
            case .success(let value):
                if !value.isEmpty {
                    let resp = NetworkResp();
                    resp.setText(value);
                    resp.setData(response.data)
                    print(req.params)
                    let result = listener.onNetworkResponse(id: id, resp: resp, model: model)
                    var hasFrozenFlag: Bool! = false
                    for (key, value) in req.params! {
                        if key == "frozenFlag" {
                            hasFrozenFlag = true
                            break
                        }
                    }
                    if hasFrozenFlag == false {
                        self.relogin(resp: resp, listener: listener)
                    }
                    
                    if result is NetworkErr {
                        let r = result as! NetworkErr;
                        if r.code != NetworkStatus.kAccountFreeze || hasFrozenFlag == true {
                            listener.onNetworkErr(id: id, err: r);
                        }
                    } else if result == nil {
                        let r: NetworkErr = NetworkErr()
                        r.message = "服务器错误"
                        listener.onNetworkErr(id: id, err: r);
                    } else {
                        listener.onNetworkSuccess(id: id, result: result as AnyObject);
                    }
                }
            case .failure(let Error):
                
                let err = Error._code
                switch err {
                case NetDisableCode.over.rawValue:
                    listener.onNetworkDisable(.over)
                    break
                default:
                    listener.onNetworkDisable(.dis)
                    break
                }
                
//                listener.onNetworkErr(id: id, err: ParseErr(id, JXLanguageTool.language(String.localized_Common_tips_netDisable));
            }
        }
    }
    
    internal func relogin(resp: NetworkResp, listener: OnNetworkListener) {
        let json = JSON(resp.getData())
        if json == nil {
            return
        }
        let model: ReqResultModel = JSONDeserializer.deserializeFrom(json: resp.getText())!
        if model.code == NetworkStatus.kUserRelogin {
            //切换rootviewcon到login
            ProgressHUD.error(model.err!)
            let appDelegate = UIApplication.shared.delegate as! AppDelegateEx
            appDelegate.reSetLoginViewCon(false, model.err!)
        } else if model.code == NetworkStatus.kAccountFreeze {
            let appDelegate = UIApplication.shared.delegate as! AppDelegateEx
            appDelegate.reSetLoginViewCon(true, model.err!)
        }
    }
    
    
    
    internal func download(id: Int, req: NetworkReq, listener: OnNetworkListener) {
        //指定下载路径和保存文件名
       let destination: DownloadRequest.DownloadFileDestination = { _, response in
            let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            let temp = documentsURL.appendingPathComponent(ConstantsEx.kDownloadPath);
            var fileURL:URL?;
        
            if let _ = req.destination {
                fileURL = temp.appendingPathComponent(req.destination!)
//                fileURL = URL.init(string: req.destination!)
            } else {
//                fileURL = temp.appendingPathComponent("temp")
            }
            print("下载地址为：\(fileURL?.absoluteString)")
            //两个参数表示如果有同名文件则会覆盖，如果路径中文件夹不存在则会自动创建
            return (fileURL!, [.removePreviousFile, .createIntermediateDirectories])
        }
        
        let downloadReq = Alamofire.download(req.url!, to: destination);
        
        downloadReq.downloadProgress { (progress) in
            print("当前进度: \(progress.fractionCompleted)")
            listener.onNetworkProgress(id: id, progress: Float(progress.fractionCompleted), total: Int(progress.totalUnitCount))
        }
        
        downloadReq.responseData { (responseData) in
            if responseData.response?.statusCode == ConstantsEx.kNetworkStatusCode200 {
                if let data = responseData.value {
//                    let cachePath = NSHomeDirectory() + "/abc.jpg";
//                    let cachePathUrl = URL(fileURLWithPath: cachePath)
//                    do {
//                        try data.write(to: cachePathUrl)
//                        print("write success")
//                    } catch {
//                        print("write failue")
//                    }
                    listener.onNetworkSuccess(id: id, result: data as AnyObject);
                }
            } else {
                print("download failure \(String(describing: responseData.response?.statusCode))")
                if responseData.response?.statusCode != nil {
                    listener.onNetworkErr(id: id, err: NetworkErr((responseData.response?.statusCode)!,"download failure"))
                }
            }
        }
    }

    final func upload<T: HandyJSON>(id: Int, req: NetworkReq, listener: OnNetworkListener, model: T) {
        Alamofire.upload(multipartFormData: { (mData) in
            mData.append(req.fileArrs![0] as! Data, withName: "file", fileName: "", mimeType: "image/jpeg/png")
            for (key, value) in req.params! {
                mData.append(value.data(using: String.Encoding.utf8)!, withName: key)
            }
        },
                         usingThreshold: 100000000,
                         to: URL.init(string: req.url!)!,
                         method: HTTPMethod.post,
                         headers: req.headers)
        { (encodingResult) in
            switch encodingResult {
            case .success(let upload, _, _):
                upload.responseJSON { response in
                    print("\(response)")
                    
                    let resp = NetworkResp();
                    resp.setText(NSString(data: response.data!, encoding: String.Encoding.utf8.rawValue)! as String);
                    resp.setData(response.data)
                    let result = listener.onNetworkResponse(id: id, resp: resp, model: model)
                    
                    if resp.getText() == String() {
                        
                        listener.onNetworkDisable(.dis)
                        return
                    }
                    
                    if result is NetworkErr {
                        let r = result as! NetworkErr;
                        listener.onNetworkErr(id: id, err: r);
                        
                    } else {
                        listener.onNetworkSuccess(id: id, result: result as AnyObject);
                    }
                }
                break
            case .failure(let Error):
                let err = Error._code
                switch err {
                case NetDisableCode.over.rawValue:
                    listener.onNetworkDisable(.over)
                    break
                default:
                    listener.onNetworkDisable(.dis)
                    break
                }
//                listener.onNetworkErr(id: id, err: ParseErr(id, JXLanguageTool.language(String.localized_Common_tips_netDisable));
                break
            default:
                print("default")
            }
        }
    }
}
